home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
widgets.zip
/
WIDGET.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-22
|
20KB
|
862 lines
// WIDGET.C
//
// David Stafford
//
// The widget-works. Dirt-simple graphical object library for Windows.
//
// 11/25/91 first alpha
// 12/12/91 added GetNextWidget, GetWidgetValuePtr
// 01/07/92 new flicker-free (but more complicated) PaintWidget
// 01/09/92 added IntersectWidgetRect, AbsHideWidget, AbsShowWidget
// 01/17/92 replaced UserValue with 'Extra' bytes
// 01/18/92 added GetWidgetMask, GetWidgetImage. Removed InternalGetWidget
// 01/21/92 added WidgetsOverlap
// 01/23/92 improved DrawBitmap and PaintWidget (added DrawHelper)
#include <windows.h>
#include <stdlib.h>
#include "widget.h"
static HWIDGET FirstWidget = NULL;
// Combines two bitmaps together to produce a third bitmap.
// ROP-code goes in the BitBlt.
// If Dest is NULL, it is created for you.
// Returns destination bitmap.
//
// This function can be used to duplicate a bitmap by specifying Dest as
// NULL and the original as both Src1 and Src2 and the Rop as SRCCOPY.
HBITMAP CDIST PASCAL CombineBitmaps( HBITMAP Dest, HBITMAP Src1, HBITMAP Src2, DWORD Rop )
{
HDC DC1, DC2;
BITMAP BitInfo;
DC1 = CreateCompatibleDC( NULL );
DC2 = CreateCompatibleDC( NULL );
GetObject( Src1, sizeof( BITMAP ), (LPSTR)&BitInfo );
if( !Dest ) Dest = CreateBitmapIndirect( &BitInfo );
SelectObject( DC1, Dest );
SelectObject( DC2, Src1 );
BitBlt( DC1,
0,
0,
BitInfo.bmWidth,
BitInfo.bmHeight,
DC2,
0,
0,
SRCCOPY );
SelectObject( DC2, Src2 );
BitBlt( DC1,
0,
0,
BitInfo.bmWidth,
BitInfo.bmHeight,
DC2,
0,
0,
Rop );
DeleteDC( DC1 );
DeleteDC( DC2 );
return( Dest );
}
// Used by DrawBitmap and PaintWidget to do the real work.
static void DrawHelper( HDC DC, int x, int y, int Width, int Height, HBITMAP Image, HBITMAP Mask )
{
HDC MemDC = CreateCompatibleDC( NULL );
HDC AnotherDC = CreateCompatibleDC( NULL );
HBITMAP WorkBM;
WorkBM = CreateCompatibleBitmap( DC, Width, Height );
SelectObject( MemDC, WorkBM );
BitBlt( MemDC,
0,
0,
Width,
Height,
DC,
x,
y,
SRCCOPY );
if( Mask )
{
SelectObject( AnotherDC, Mask );
BitBlt( MemDC,
0,
0,
Width,
Height,
AnotherDC,
0,
0,
SRCAND );
}
SelectObject( AnotherDC, Image );
BitBlt( MemDC,
0,
0,
Width,
Height,
AnotherDC,
0,
0,
Mask ? SRCINVERT : SRCCOPY );
BitBlt( DC,
x,
y,
Width,
Height,
MemDC,
0,
0,
SRCCOPY );
DeleteDC( MemDC );
DeleteDC( AnotherDC );
DeleteObject( WorkBM );
}
// Just draws a simple bitmap on the display.
// The mask is optional.
void CDIST PASCAL DrawBitmap( HDC DC, int x, int y, HBITMAP Image, HBITMAP Mask )
{
BITMAP BitInfo;
GetObject( Image, sizeof( BITMAP ), (LPSTR)&BitInfo );
DrawHelper( DC,
x,
y,
BitInfo.bmWidth,
BitInfo.bmHeight,
Image,
Mask );
}
// Internal function to save the background image behind the widget in a bitmap.
static void SaveWidgetBackground( HDC DC, HWIDGET Widget )
{
HDC MemDC = CreateCompatibleDC( NULL );
if( !Widget->Background )
{
Widget->Background = CreateCompatibleBitmap( DC, Widget->Size.x, Widget->Size.y );
}
SelectObject( MemDC, Widget->Background );
BitBlt( MemDC,
0,
0,
Widget->Size.x,
Widget->Size.y,
DC,
Widget->Rect.left,
Widget->Rect.top,
SRCCOPY );
DeleteDC( MemDC );
}
// Internal function to restore the background image behind the widget.
static void RestoreWidgetBackground( HDC DC, HWIDGET Widget )
{
HDC MemDC = CreateCompatibleDC( NULL );
SelectObject( MemDC, Widget->Background );
BitBlt( DC,
Widget->Rect.left,
Widget->Rect.top,
Widget->Size.x,
Widget->Size.y,
MemDC,
0,
0,
SRCCOPY );
DeleteDC( MemDC );
DeleteObject( Widget->Background );
Widget->Background = NULL;
}
// Internal function to paint a widget on the screen.
// The DC can be NULL
static void PaintWidget( HDC DC, HWIDGET Widget )
{
HDC TempDC = DC;
if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
DrawHelper( TempDC,
Widget->Rect.left,
Widget->Rect.top,
Widget->Size.x,
Widget->Size.y,
Widget->Image,
Widget->Mask );
if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
}
// Creates a new widget. The mask is optional (use NULL if it doesn't exist).
// The widget is initially hidden and put at location 0,0.
HWIDGET CDIST PASCAL CreateWidget( HWND Wnd, HBITMAP Image, HBITMAP Mask, int Extra )
{
WIDGET *Widget;
BITMAP BitInfo;
if( (Widget = (WIDGET *)LocalAlloc( LMEM_FIXED, sizeof( WIDGET ) + Extra )) != NULL )
{
GetObject( Image, sizeof( BITMAP ), (LPSTR)&BitInfo );
Widget->Wnd = Wnd;
Widget->Size.x = BitInfo.bmWidth;
Widget->Size.y = BitInfo.bmHeight;
Widget->Rect.left = 0;
Widget->Rect.top = 0;
Widget->Rect.right = BitInfo.bmWidth;
Widget->Rect.bottom = BitInfo.bmHeight;
Widget->Image = Image;
Widget->Mask = Mask;
Widget->Visible = 0;
Widget->Background = NULL;
Widget->Next = FirstWidget;
FirstWidget = Widget;
}
return( Widget );
}
// Moves a widget to a new location.
// The DC can be NULL.
void CDIST PASCAL MoveWidget( HDC DC, HWIDGET Widget, int x, int y )
{
RECT NewRect, OldRect, Union;
POINT UnionSize;
HDC WorkDC, ScratchDC, TempDC = DC;
HBITMAP WorkBM;
if( Widget->Rect.left == x && Widget->Rect.top == y ) return;
NewRect.left = x;
NewRect.top = y;
NewRect.right = x + Widget->Size.x;
NewRect.bottom = y + Widget->Size.y;
if( !IsWidgetVisible( Widget ) )
{
Widget->Rect = NewRect;
return;
}
if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
if( IntersectRect( &Union, &NewRect, &Widget->Rect ) )
{
UnionRect( &Union, &NewRect, &Widget->Rect );
UnionSize.x = Union.right - Union.left;
UnionSize.y = Union.bottom - Union.top;
WorkDC = CreateCompatibleDC( NULL );
WorkBM = CreateCompatibleBitmap( TempDC, UnionSize.x, UnionSize.y );
SelectObject( WorkDC, WorkBM );
BitBlt( WorkDC,
0,
0,
UnionSize.x,
UnionSize.y,
TempDC,
Union.left,
Union.top,
SRCCOPY );
ScratchDC = CreateCompatibleDC( NULL );
SelectObject( ScratchDC, Widget->Background );
BitBlt( WorkDC,
Widget->Rect.left - Union.left,
Widget->Rect.top - Union.top,
Widget->Size.x,
Widget->Size.y,
ScratchDC,
0,
0,
SRCCOPY );
BitBlt( ScratchDC,
0,
0,
Widget->Size.x,
Widget->Size.y,
WorkDC,
NewRect.left - Union.left,
NewRect.top - Union.top,
SRCCOPY );
if( Widget->Mask )
{
SelectObject( ScratchDC, Widget->Mask );
BitBlt( WorkDC,
NewRect.left - Union.left,
NewRect.top - Union.top,
Widget->Size.x,
Widget->Size.y,
ScratchDC,
0,
0,
SRCAND );
}
SelectObject( ScratchDC, Widget->Image );
BitBlt( WorkDC,
NewRect.left - Union.left,
NewRect.top - Union.top,
Widget->Size.x,
Widget->Size.y,
ScratchDC,
0,
0,
Widget->Mask ? SRCINVERT : SRCCOPY );
DeleteDC( ScratchDC );
#if 0
// wait for vertical retrace
__emit__( 0xba, 0xda, 0x03, // mov dx,03dah
0xec, // wait1: in al,dx
0xa8, 0x08, // test al,8
0x75, 0xfb, // jnz wait1
0xec, // wait2: in al,dx
0xa8, 0x08, // test al,8
0x74, 0xfb ); // jz wait2
#endif
BitBlt( TempDC,
Union.left,
Union.top,
UnionSize.x,
UnionSize.y,
WorkDC,
0,
0,
SRCCOPY );
DeleteDC( WorkDC );
DeleteObject( WorkBM );
Widget->Rect = NewRect;
}
else
{
HideWidget( TempDC, Widget );
Widget->Rect = NewRect;
ShowWidget( TempDC, Widget );
}
if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
}
void FAR PASCAL LineDDAProc( int x, int y, ANIM_DATA FAR *Anim )
{
DWORD TimeUsed = GetTickCount() - Anim->StartTime;
WORD Budget = ((DWORD)Anim->Count * Anim->Speed) / Anim->Distance;
if( TimeUsed <= Budget )
{
MoveWidget( Anim->DC, Anim->Widget, x, y );
Yield(); // give background apps a chance
}
++Anim->Count;
}
// Returns the number of pixels between two points.
// (Not the exact distance.)
// This is useful when you want to select the speed for the animation
// so it remains somewhat constant across varying distances.
int CDIST PASCAL DistanceInPoints( int x1, int y1, int x2, int y2 )
{
return( max( abs( x1 - x2 ), abs( y1 - y2 ) ) + 1 );
}
// Animates a widget to a new location.
// The DC can be NULL.
// The speed is the number of milliseconds between animations.
// Instance should be NULL if linked with the DLL version.
void CDIST PASCAL AnimateWidget( HDC DC, HWIDGET Widget, int x, int y, int Speed, HANDLE Instance )
{
ANIM_DATA Anim;
FARPROC LineProc;
Anim.Widget = Widget;
Anim.DC = DC;
Anim.Speed = Speed;
Anim.StartTime = GetTickCount();
Anim.Distance = DistanceInPoints( x, y, Widget->Rect.left, Widget->Rect.top );
Anim.Count = 0;
#ifdef LINKABLE
LineProc = MakeProcInstance( (FARPROC)LineDDAProc, Instance );
LineDDA( Widget->Rect.left,
Widget->Rect.top,
x,
y,
LineProc,
(LPSTR)&Anim );
FreeProcInstance( (FARPROC)LineProc );
#else
LineDDA( Widget->Rect.left,
Widget->Rect.top,
x,
y,
(FARPROC)LineDDAProc,
(LPSTR)&Anim );
#endif
MoveWidget( DC, Widget, x, y );
}
// Destroys a widget. Does not erase it from the display.
// You must use HideWidget first.
void CDIST PASCAL DestroyWidget( HWIDGET Widget )
{
HWIDGET Prev;
if( Widget->Background ) DeleteObject( Widget->Background );
if( Widget == FirstWidget )
{
FirstWidget = Widget->Next;
}
else
{
for( Prev = FirstWidget; Prev->Next != Widget; Prev = Prev->Next )
;
Prev->Next = Widget->Next;
}
LocalFree( (HANDLE)Widget );
}
// Just like the name says. Widget-cide.
void CDIST PASCAL DestroyAllWidgetsForTheWindow( HWND Wnd )
{
HWIDGET Widget;
while( (Widget = GetNextWidget( Wnd, NULL )) != NULL )
{
DestroyWidget( Widget );
}
}
// Decrements the widget's visibility count and hides it if the count is <= 0.
// The DC can be NULL.
void CDIST PASCAL HideWidget( HDC DC, HWIDGET Widget )
{
HDC TempDC = DC;
if( --Widget->Visible == 0 )
{
if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
RestoreWidgetBackground( TempDC, Widget );
if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
}
}
// Hides a widget. Restores the background.
// The DC can be NULL.
void CDIST PASCAL AbsHideWidget( HDC DC, HWIDGET Widget )
{
while( IsWidgetVisible( Widget ) ) HideWidget( DC, Widget );
}
// Increments the widget's visibility count and shows it if the count is > 0.
// The DC can be NULL.
void CDIST PASCAL ShowWidget( HDC DC, HWIDGET Widget )
{
HDC TempDC = DC;
if( ++Widget->Visible == 1 )
{
if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
SaveWidgetBackground( TempDC, Widget );
PaintWidget( TempDC, Widget );
if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
}
}
// Makes a widget visible.
// The DC can be NULL.
void CDIST PASCAL AbsShowWidget( HDC DC, HWIDGET Widget )
{
while( !IsWidgetVisible( Widget ) ) ShowWidget( DC, Widget );
}
// Used to dynamically change the look of a widget.
// The DC can be NULL.
void CDIST PASCAL ChangeWidgetImage( HDC DC, HWIDGET Widget, HBITMAP Image, HBITMAP Mask )
{
BITMAP BitInfo;
int Visible;
if( Widget->Image != Image )
{
if( Widget->Mask == Mask ) // if the mask didn't change it's much faster!
{
Widget->Image = Image;
if( IsWidgetVisible( Widget ) ) PaintWidget( DC, Widget );
}
else
{
if( (Visible = Widget->Visible) > 0 ) AbsHideWidget( DC, Widget );
GetObject( Image, sizeof( BITMAP ), (LPSTR)&BitInfo );
Widget->Size.x = BitInfo.bmWidth;
Widget->Size.y = BitInfo.bmHeight;
Widget->Rect.right = Widget->Rect.left + BitInfo.bmWidth;
Widget->Rect.bottom = Widget->Rect.top + BitInfo.bmHeight;
Widget->Image = Image;
Widget->Mask = Mask;
if( Visible > 0 ) ShowWidget( DC, Widget );
Widget->Visible = Visible;
}
}
}
// Invalidates any widgets which might be only partially obscured.
// Sets the dirty flag for the redraw in RepaintWidgets.
// Use this first in your WM_PAINT handler.
void CDIST PASCAL InvalidateWidgetsForPaint( HWND Wnd )
{
HWIDGET Widget;
HRGN Rgn = CreateRectRgn( 0, 0, 1, 1 );
GetUpdateRgn( Wnd, Rgn, FALSE );
for( Widget = FirstWidget; Widget; Widget = Widget->Next )
{
if( Widget->Wnd == Wnd )
{
Widget->Dirty = FALSE;
if( IsWidgetVisible( Widget ) )
{
if( RectInRegion( Rgn, &Widget->Rect ) )
{
Widget->Dirty = TRUE;
InvalidateRect( Wnd, &Widget->Rect, FALSE );
}
}
}
}
DeleteObject( Rgn );
}
// Repaints all the widgets belonging to a given window.
// Use this after InvalidateWidgetsForPaint and the background
// redraw in your WM_PAINT handler.
void CDIST PASCAL RepaintWidgets( HDC DC, HWND Wnd )
{
HWIDGET Widget;
for( Widget = FirstWidget; Widget; Widget = Widget->Next )
{
if( Widget->Wnd == Wnd )
{
if( Widget->Dirty )
{
SaveWidgetBackground( DC, Widget );
PaintWidget( DC, Widget );
}
}
}
}
// Determines if a point is inside a widget.
// The point is a pixel coordinate relative to the window.
BOOL CDIST PASCAL IsPointInWidget( HWIDGET Widget, int x, int y )
{
POINT Pt;
HDC MemDC;
BOOL Res = FALSE;
Pt.x = x;
Pt.y = y;
if( PtInRect( &Widget->Rect, Pt ) )
{
if( Widget->Mask == NULL )
{
Res = TRUE;
}
else
{
MemDC = CreateCompatibleDC( NULL );
SelectObject( MemDC, Widget->Mask );
Res = GetPixel( MemDC, x - Widget->Rect.left, y - Widget->Rect.top ) == RGB( 0, 0, 0 );
DeleteDC( MemDC );
}
}
return( Res );
}
// Determines which widget lies at a given point in a window.
// The point is a pixel coordinate relative to the window.
HWIDGET CDIST PASCAL WidgetHitTest( HWND Wnd, int x, int y )
{
HWIDGET Widget;
POINT Pt;
HDC MemDC = CreateCompatibleDC( NULL );
Pt.x = x;
Pt.y = y;
for( Widget = FirstWidget; Widget; Widget = Widget->Next )
{
if( Widget->Wnd == Wnd && IsWidgetVisible( Widget ) )
{
if( PtInRect( &Widget->Rect, Pt ) )
{
if( Widget->Mask == NULL ) break;
SelectObject( MemDC, Widget->Mask );
if( GetPixel( MemDC, x - Widget->Rect.left, y - Widget->Rect.top ) == RGB( 0, 0, 0 ) ) break;
}
}
}
DeleteDC( MemDC );
return( Widget );
}
// Determines if a widget intersects a given rectangle.
// If Inter is not NULL it will set it to the intersection.
BOOL CDIST PASCAL IntersectWidgetRect( HWIDGET Widget, RECT DDIST *Rect, RECT DDIST *Inter )
{
BOOL Ret;
RECT Dest;
Ret = IntersectRect( &Dest, &Widget->Rect, Rect );
if( Inter ) *Inter = Dest;
return( Ret );
}
// Useful for enumerating all the widgets for a window.
// Use NULL as the widget to get the first widget.
// Returns the next widget or NULL if at the end of the list.
HWIDGET CDIST PASCAL GetNextWidget( HWND Wnd, HWIDGET Widget )
{
if( Widget == NULL ) Widget = FirstWidget;
else Widget = Widget->Next;
while( Widget && Widget->Wnd != Wnd )
{
Widget = Widget->Next;
}
return( Widget );
}
// Determines if one widget overlaps another.
//
// Note that this test uses only the widget rectangles and
// isn't as precise as a test which would take into account
// the masks. But, this is good enough for now.
//
// If Widget2 is NULL all widgets in the same window are tested.
BOOL CDIST PASCAL WidgetsOverlap( HWIDGET Widget1, HWIDGET Widget2 )
{
RECT Dummy;
if( Widget2 )
{
if( !IsWidgetVisible( Widget2 ) ) return( FALSE );
return( IntersectRect( &Dummy, &Widget1->Rect, &Widget2->Rect ) );
}
else
{
while( (Widget2 = GetNextWidget( Widget1->Wnd, Widget2 )) != NULL )
{
if( Widget2 != Widget1 && IsWidgetVisible( Widget2 ) )
{
if( IntersectRect( &Dummy, &Widget1->Rect, &Widget2->Rect ) )
{
return( TRUE );
}
}
}
return( FALSE );
}
}
////////////////////////////////////////////////////////////////////////////
#ifndef LINKABLE
BOOL CDIST PASCAL IsWidgetVisible( HWIDGET Widget )
{
return( Widget->Visible > 0 );
}
POINT CDIST PASCAL GetWidgetPoint( HWIDGET Widget )
{
return( *(POINT *)&(Widget->Rect.left) );
}
HBITMAP CDIST PASCAL GetWidgetImage( HWIDGET Widget )
{
return( Widget->Image );
}
HBITMAP CDIST PASCAL GetWidgetMask( HWIDGET Widget )
{
return( Widget->Mask );
}
POINT CDIST PASCAL GetWidgetSize( HWIDGET Widget )
{
return( Widget->Size );
}
void CDIST PASCAL GetWidgetRect( HWIDGET Widget, RECT DDIST *Rect )
{
*Rect = Widget->Rect;
}
void DDIST * CDIST PASCAL GetWidgetExtra( HWIDGET Widget )
{
return( ((char *)(Widget) + sizeof( WIDGET )) );
}
// Returns the version number of the Widget DLL.
int CDIST PASCAL GetVersionNumber( void )
{
return( 4 );
}
int CDIST PASCAL LibMain( HANDLE Module, WORD DataSeg, WORD HeapSize, LPSTR CmdLine )
{
return( 1 );
}
int CDIST PASCAL WEP( int SystemExit )
{
return( 1 );
}
#endif